home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / comm / mail / YAM23src.lha / Source / YAM_TR.c < prev    next >
C/C++ Source or Header  |  2001-05-08  |  67KB  |  1,925 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 1995-2000 by Marcel Beck <mbeck@yam.ch>
  5.  Copyright (C) 2000-2001 by YAM Open Source Team
  6.  
  7.  This program is free software; you can redistribute it and/or modify
  8.  it under the terms of the GNU General Public License as published by
  9.  the Free Software Foundation; either version 2 of the License, or
  10.  (at your option) any later version.
  11.  
  12.  This program is distributed in the hope that it will be useful,
  13.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  GNU General Public License for more details.
  16.  
  17.  You should have received a copy of the GNU General Public License
  18.  along with this program; if not, write to the Free Software
  19.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  
  21.  YAM Official Support Site :  http://www.yam.ch
  22.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  23.  
  24.  $Id: YAM_TR.c,v 1.19 2001/05/08 22:27:37 damato Exp $
  25.  
  26. ***************************************************************************/
  27.  
  28. #include "YAM.h"
  29. #include <md5.h>
  30.  
  31. /***************************************************************************
  32.  Module: Transfer
  33. ***************************************************************************/
  34.  
  35. /*** General connecting/disconnecting & transfer ***/
  36.  
  37. /// TR_IsOnline
  38. //  Checks if there's an online connection
  39. #ifdef __STORM__
  40. extern struct Library *GenesisBase;
  41. struct Library *MiamiBase, *SoBase;
  42. #endif
  43. BOOL TR_IsOnline(void)
  44. {
  45.    BOOL isonline = FALSE;
  46. #ifndef __STORM__
  47.    struct Library *MiamiBase, *GenesisBase, *SoBase;
  48. #endif
  49.  
  50.    if (C->IsOnlineCheck)
  51.    {
  52.       if (MiamiBase = OpenLibrary(MIAMINAME, 10))
  53.       {
  54.          isonline = MiamiIsOnline(*C->IOCInterface ? C->IOCInterface : NULL); CloseLibrary(MiamiBase);
  55.          return isonline;
  56.       }
  57.       else if (GenesisBase = OpenLibrary("genesis.library", 1))
  58.       {
  59.          isonline = IsOnline(*C->IOCInterface ? (long)C->IOCInterface : NULL); CloseLibrary(GenesisBase);
  60.          return isonline;
  61.       }
  62.    }
  63.    if (SoBase = OpenLibrary("bsdsocket.library", 2L))
  64.    {
  65.       isonline = TRUE; CloseLibrary(SoBase);
  66.    }
  67.    return isonline;
  68. }
  69. ///
  70. /// TR_CloseTCPIP
  71. //  Closes bsdsocket library
  72. void TR_CloseTCPIP(void)
  73. {
  74.    if (SocketBase) CloseLibrary(SocketBase);
  75.    SocketBase = NULL;
  76. }
  77. ///
  78. /// TR_OpenTCPIP
  79. //  Opens bsdsocket.library
  80. BOOL TR_OpenTCPIP(void)
  81. {
  82.    if (!TR_IsOnline()) return FALSE;
  83.    if (!SocketBase) SocketBase = OpenLibrary("bsdsocket.library", 2L);
  84.    return (BOOL)(SocketBase != NULL);
  85. }
  86. ///
  87. /// TR_Disconnect
  88. //  Terminates a connection
  89. void TR_Disconnect(void)
  90. {
  91.    if (G->TR_Socket != SMTP_NO_SOCKET)
  92.    {
  93.       Shutdown(G->TR_Socket, 2);
  94.       CloseSocket(G->TR_Socket);
  95.       G->TR_Socket = SMTP_NO_SOCKET;
  96.    }
  97. }
  98. ///
  99. /// TR_Connect
  100. //  Connects to a internet service
  101. int TR_Connect(char *host, int port)
  102. {
  103.    struct hostent *hostaddr;
  104.  
  105.    if (!(hostaddr = GetHostByName((STRPTR)host))) return -1;
  106.    G->TR_INetSocketAddr.sin_len = sizeof(G->TR_INetSocketAddr);
  107.    G->TR_INetSocketAddr.sin_family = AF_INET;
  108.    G->TR_INetSocketAddr.sin_port = port;
  109.    G->TR_INetSocketAddr.sin_addr.s_addr = 0;
  110.    memcpy(&G->TR_INetSocketAddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
  111.  
  112.    G->TR_Socket = Socket(hostaddr->h_addrtype, SOCK_STREAM, 0);
  113.    if (G->TR_Socket == -1) {
  114.       TR_Disconnect();
  115.       return -2;
  116.    }
  117.  
  118.    if (Connect(G->TR_Socket, (struct sockaddr *)&G->TR_INetSocketAddr, sizeof(G->TR_INetSocketAddr)) != -1) {
  119.       return 0;
  120.    }
  121.    if (Errno() == EINPROGRESS) return 0;
  122.    /* Preparation for non-blocking I/O */
  123.  
  124.    TR_Disconnect();
  125.    return -3;
  126. }
  127. ///
  128. /// TR_RecvDat
  129. //  Receives data from a TCP/IP connection
  130. int TR_RecvDat(char *recvdata)                   /* success? */
  131. {
  132.    int len;
  133.  
  134.    DoMethod(G->App,MUIM_Application_InputBuffered);
  135.    if (G->TR_Socket == SMTP_NO_SOCKET) return 0;
  136.    len = Recv(G->TR_Socket, (STRPTR)recvdata, SIZE_LINE-1, 0);
  137.    if (len <= 0) recvdata[0]=0;
  138.    else recvdata[len] = '\0';
  139.    if (G->TR_Debug) printf("SERVER: %s", recvdata);
  140.    return len;
  141. }
  142. ///
  143. /// TR_SendDat
  144. //  Sends data through a TCP/IP connection
  145. BOOL TR_SendDat(char *senddata)                  /* success? */
  146. {
  147.    DoMethod(G->App,MUIM_Application_InputBuffered);
  148.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  149.    if (!senddata) return TRUE;
  150.    if (G->TR_Debug) printf("CLIENT: %s", senddata);
  151.    if (Send(G->TR_Socket, (STRPTR)senddata, strlen(senddata), 0) != -1) return TRUE;
  152.    return FALSE;
  153. }
  154. ///
  155. /// TR_SetWinTitle
  156. //  Sets the title of the transfer window
  157. void TR_SetWinTitle(BOOL from, char *host)
  158. {
  159.    sprintf(G->TR->WTitle, GetStr(from ? MSG_TR_MailTransferFrom : MSG_TR_MailTransferTo), host);
  160.    set(G->TR->GUI.WI, MUIA_Window_Title, G->TR->WTitle);
  161. }
  162. ///
  163.  
  164. /*** HTTP routines ***/
  165. /// TR_DownloadURL
  166. //  Downloads a file from the web using HTTP
  167. BOOL TR_DownloadURL(char *url0, char *url1, char *url2, char *filename)
  168. {
  169.    
  170.    BOOL success = FALSE, done = FALSE, noproxy = !*C->ProxyServer;
  171.    int l = 0, len, hport;
  172.    char buf[SIZE_LINE], url[SIZE_URL], host[SIZE_HOST], *port, *path, line[SIZE_DEFAULT], *bufptr;
  173.    FILE *out;
  174.  
  175.    G->Error = FALSE;
  176.    if (!strnicmp(url0,"http://",7)) strcpy(url, &url0[7]); else strcpy(url, url0);
  177.    if (url1)
  178.    {
  179.       if (url[strlen(url)-1] != '/') strcat(url, "/");
  180.       strcat(url, url1);
  181.    }
  182.    if (url2)
  183.    {
  184.       if (url[strlen(url)-1] != '/') strcat(url, "/");
  185.       strcat(url, url2);
  186.    }
  187.    if (path = strchr(url,'/')) *path++ = 0; else path = "";
  188.    strcpy(host, noproxy ? url : C->ProxyServer);
  189.    if (bufptr = strchr(host, ':')) { *bufptr++ = 0; hport = atoi(bufptr); }
  190.    else hport = noproxy ? 80 : 8080;
  191.    if (!TR_Connect(host, hport))
  192.    {
  193. /*
  194.       if (noproxy) sprintf(buf, "GET /%s HTTP/1.0\r\nHost: http://%s\r\n", path, host);
  195.       else if (port = strchr(url, ':'))
  196.       {
  197.          *port++ = 0;
  198.          sprintf(buf, "GET http://%s:%s/%s HTTP/1.0\r\nHost: http://%s\r\n", url, port, path, url);
  199.       }
  200.       else sprintf(buf, "GET http://%s/%s HTTP/1.0\r\nHost: http://%s\r\n", url, path, url);
  201.       sprintf(&buf[strlen(buf)], "From: %s\r\nUser-Agent: YAM %s\r\n\r\n", BuildAddrName(C->EmailAddress, C->RealName), __YAM_VERSION);
  202. */
  203.       if (noproxy) sprintf(buf, "GET /%s HTTP/1.0\r\nHost: %s\r\n", path, host);
  204.       else if (port = strchr(url, ':'))
  205.       {
  206.          *port++ = 0;
  207.          sprintf(buf, "GET http://%s:%s/%s HTTP/1.0\r\nHost: %s\r\n", url, port, path, url);
  208.       }
  209.       else sprintf(buf, "GET http://%s/%s HTTP/1.0\r\nHost: %s\r\n", url, path, url);
  210.       sprintf(&buf[strlen(buf)], "From: %s\r\nUser-Agent: YAM %s\r\n\r\n", BuildAddrName(C->EmailAddress, C->RealName), __YAM_VERSION);
  211.       if (TR_SendDat(buf))
  212.       {
  213.          len = TR_RecvDat(buf);
  214.          if (atoi(&buf[9]) == 200)
  215.          {
  216.             if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  217.             while (!G->Error)
  218.             {
  219.                for (; *bufptr; bufptr++)
  220.                {
  221.                   if (*bufptr != '\r') if (l < SIZE_DEFAULT-1) line[l++] = *bufptr;
  222.                   if (*bufptr != '\n') continue;
  223.                   line[l] = 0; l = 0;
  224.                   if (line[0] == '\n') { done = TRUE; break; }
  225.                }
  226.                if (done) break;
  227.                if ((len = TR_RecvDat(buf)) <= 0) break;
  228.                bufptr = buf;
  229.             }
  230.             if (out = fopen(filename, "w"))
  231.             {
  232.                ++bufptr;
  233.                fwrite(bufptr, len-(bufptr-buf), 1, out);
  234.                while ((len = TR_RecvDat(buf)) > 0) fwrite(buf, len, 1, out);
  235.                fclose(out);
  236.                success = TRUE;
  237.             }
  238.             else ER_NewError(GetStr(MSG_ER_CantCreateFile), filename, NULL);
  239.          }
  240.          else ER_NewError(GetStr(MSG_ER_DocNotFound), path, NULL);
  241.       }
  242.       else ER_NewError(GetStr(MSG_ER_SendHTTP), NULL, NULL);
  243.       TR_Disconnect();
  244.    }
  245.    else ER_NewError(GetStr(MSG_ER_ConnectHTTP), host, NULL);
  246.    return success;
  247. }
  248. ///
  249.  
  250. /*** POP3 routines ***/
  251. /// TR_SendPopCmd
  252. //  Sends a command to the POP3 server
  253. BOOL TR_SendPopCmd(char *buf, char *cmdtext, char *parmtext, int flags)
  254. {
  255.    char cmdbuf[SIZE_COMMAND];
  256.    int len, ln;
  257.  
  258.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  259.    if (!parmtext || !*parmtext) sprintf(cmdbuf, "%s\r\n", cmdtext);
  260.    else sprintf(cmdbuf, "%s %s\r\n", cmdtext, parmtext);
  261.    if (!TR_SendDat(cmdbuf)) return FALSE;
  262.    len = TR_RecvDat(buf);
  263.    if (len <= 0)  return FALSE;
  264.    if (flags & POPCMD_WAITEOL)
  265.    {
  266.       while (buf[len-1] != '\n')
  267.       {
  268.          ln = TR_RecvDat(&buf[len]);
  269.          if (ln > 0) len += ln; else return FALSE;
  270.       }
  271.    }
  272.    if (!strncmp(buf, "-ERR", 4))
  273.    {
  274.       if (!(flags & POPCMD_NOERROR)) ER_NewError(GetStr(MSG_ER_BadResponse), cmdtext, buf);
  275.       return FALSE;
  276.    }
  277.    return TRUE;
  278. }
  279. ///
  280. /// TR_ConnectPOP
  281. //  Connects to a POP3 mail server
  282. int TR_ConnectPOP(int guilevel)
  283. {     
  284.    char passwd[SIZE_PASSWORD], host[SIZE_HOST], buf[SIZE_LINE], *p;
  285.    int err, pop = G->TR->POP_Nr, msgs, port = 110;
  286.  
  287.    strcpy(passwd, C->P3[pop]->Password);
  288.    strcpy(host, C->P3[pop]->Server);
  289.    if (C->TransferWindow == 2 || (C->TransferWindow == 1 && (guilevel == POP_START || guilevel == POP_USER)))
  290.    {
  291.       LONG wstate;
  292.  
  293.       get(G->TR->GUI.WI, MUIA_Window_Open, &wstate);            // avoid MUIA_Window_Open's side effect of
  294.       if(!wstate) set(G->TR->GUI.WI, MUIA_Window_Open, TRUE);   // activating the window if it was already open
  295.    }
  296.    set(G->TR->GUI.TX_STATUS  , MUIA_Text_Contents,GetStr(MSG_TR_Connecting));
  297.    if (p = strchr(host, ':')) { *p = 0; port = atoi(++p); }
  298.    TR_SetWinTitle(TRUE, host);
  299.    if (err = TR_Connect(host, port))
  300.    {
  301.       if (guilevel == POP_USER) switch (err)
  302.       {
  303.          case -1: ER_NewError(GetStr(MSG_ER_UnknownPOP), C->P3[pop]->Server, NULL); break;
  304.          default: ER_NewError(GetStr(MSG_ER_CantConnect), C->P3[pop]->Server, NULL);
  305.       }
  306.       return -1;
  307.    }
  308.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_WaitWelcome));
  309.  
  310.    if (TR_RecvDat(buf) <= 0) return -1;
  311.    if (!*passwd)
  312.    {
  313.       sprintf(buf, GetStr(MSG_TR_PopLoginReq), C->P3[pop]->User, host);
  314.       if (!StringRequest(passwd, SIZE_PASSWORD, GetStr(MSG_TR_PopLogin), buf, GetStr(MSG_Okay), NULL, GetStr(MSG_Cancel), TRUE, G->TR->GUI.WI)) return -1;
  315.    }
  316.    if (C->P3[pop]->UseAPOP)
  317.    {
  318.       MD5_CTX context;
  319.       UBYTE digest[16], *welcomemsg = StrBufCpy(NULL, buf);
  320.       int i, j;
  321.  
  322.       while (!strstr(buf, "\n"))
  323.       {
  324.          if (TR_RecvDat(buf) <= 0) return -1;
  325.          welcomemsg = StrBufCat(welcomemsg, buf);
  326.       }
  327.       *buf = 0;
  328.       if (p = strchr(welcomemsg, '<'))
  329.       {
  330.          strcpy(buf, p);
  331.          if (p = strchr(buf, '>')) p[1] = 0;
  332.       }
  333.       else ER_NewError(GetStr(MSG_ER_NoAPOP), NULL, NULL);
  334.       strcat(buf, passwd);
  335.       FreeStrBuf(welcomemsg);
  336.       MD5Init(&context);
  337.       MD5Update(&context, buf, strlen(buf));
  338.       MD5Final(digest, &context);
  339.       sprintf(buf, "%s ", C->P3[pop]->User);
  340.       for (j=strlen(buf), i=0; i<16; j+=2, i++) sprintf(&buf[j], "%02x", digest[i]);
  341.       buf[j] = 0;
  342.       set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_SendAPOPLogin));
  343.       if (!TR_SendPopCmd(buf, "APOP", buf, POPCMD_WAITEOL)) return -1;
  344.    }
  345.    else
  346.    {
  347.       while (!strstr(buf, "\n")) if (TR_RecvDat(buf) <= 0) return -1;
  348.       set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_SendUserID));
  349.       if (!TR_SendPopCmd(buf, "USER", C->P3[pop]->User, POPCMD_WAITEOL)) return -1;
  350.       set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_SendPassword));
  351.       if (!TR_SendPopCmd(buf, "PASS", passwd, POPCMD_WAITEOL)) return -1;
  352.    }
  353.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_GetStats));
  354.    if (!TR_SendPopCmd(buf, "STAT", NULL, POPCMD_WAITEOL)) return -1;
  355.    sscanf(&buf[4], "%ld", &msgs);
  356.    if (msgs) AppendLogVerbose(31, GetStr(MSG_LOG_ConnectPOP), C->P3[pop]->User, host, (void *)msgs, "");
  357.    return msgs;
  358. }
  359. ///
  360. /// TR_DisplayMailList
  361. //  Displays a list of messages ready for download
  362. void TR_DisplayMailList(BOOL largeonly)
  363. {
  364.    struct Mail *mail;
  365.    APTR lv = G->TR->GUI.LV_MAILS;
  366.    int pos = 0;
  367.    set(lv, MUIA_NList_Quiet, TRUE);
  368.    for (mail = G->TR->List; mail; mail = mail->Next)
  369.       if (mail->Size >= C->WarnSize<<10 || !largeonly)
  370.       {
  371.          mail->Position = pos++;
  372.          DoMethod(lv, MUIM_NList_InsertSingle, mail, MUIV_NList_Insert_Bottom);
  373.       }
  374.    set(lv, MUIA_NList_Quiet, FALSE);
  375. }
  376. ///
  377. /// TR_AddMessageHeader
  378. //  Parses downloaded message header
  379. void TR_AddMessageHeader(int *count, int size, char *tfname)
  380. {
  381.    struct Mail *mail;
  382.    struct ExtendedMail *email;
  383.  
  384.    if (email = MA_ExamineMail((struct Folder *)-1, tfname, NULL, FALSE))
  385.    {
  386.       mail = calloc(1,sizeof(struct Mail));
  387.       *mail = email->Mail;
  388.       mail->Folder  = NULL;
  389.       mail->Status  = 1;
  390.       mail->Index   = ++(*count);
  391.       mail->Size    = size;
  392.       MA_FreeEMailStruct(email);
  393.       MyAddTail(&(G->TR->List), mail);
  394.    }
  395. }
  396. ///
  397. /// TR_GetMessageList_IMPORT
  398. //  Collects messages from a UUCP mailbox file
  399. void TR_GetMessageList_IMPORT(FILE *fh)
  400. {
  401.    BOOL body = FALSE;
  402.    int c = 0, size = 0;
  403.    char buffer[SIZE_LINE], *ptr, *tfname = "yamIMP.tmp", fname[SIZE_PATHFILE];
  404.    FILE *f = NULL;
  405.  
  406.    strmfp(fname, C->TempDir, tfname);
  407.    G->TR->List = NULL;
  408.    fseek(fh, 0, SEEK_SET);
  409.    while (fgets(buffer, SIZE_LINE, fh))
  410.    {
  411.       if (f || body) size += strlen(buffer);
  412.       if (ptr = strpbrk(buffer, "\r\n")) *ptr = 0;
  413.       if (!f && !strncmp(buffer, "From ", 5))
  414.       {
  415.          if (body) { TR_AddMessageHeader(&c, size, tfname); DeleteFile(fname); }
  416.          if (!(f = fopen(fname, "w"))) break;
  417.          size = 0; body = FALSE;
  418.       }
  419.       if (f)
  420.       {
  421.          fputs(buffer, f); fputc('\n', f);
  422.          if (!*buffer)
  423.          { 
  424.             fclose(f); f = NULL;
  425.             body = TRUE;
  426.          }
  427.       }
  428.    }
  429.    if (body) { TR_AddMessageHeader(&c, size, tfname); DeleteFile(fname); }
  430.    TR_DisplayMailList(FALSE);
  431. }
  432. ///
  433. /// TR_GetMessageList_GET
  434. //  Collects messages waiting on a POP3 server
  435. BOOL TR_GetMessageList_GET(int maxmsgs)
  436. {
  437.    char buf[SIZE_LINE];
  438.  
  439.    if (TR_SendPopCmd(buf, "LIST", NULL, 0))
  440.    {
  441.       int mode, l = 0, index, size;
  442.       char line[SIZE_DEFAULT], *bufptr;
  443.       BOOL done = FALSE;
  444.       struct Mail *new;
  445.  
  446.       G->TR->List = NULL;
  447.       if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  448.       else if (TR_RecvDat(buf) > 0) if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  449.       if (!bufptr) return FALSE;
  450.       while (!G->Error)
  451.       {
  452.          for (; *bufptr; bufptr++)
  453.          {
  454.             if (*bufptr != '\r') if (l < SIZE_DEFAULT-1) line[l++] = *bufptr;
  455.             if (*bufptr != '\n') continue;
  456.             line[l] = 0; l = 0;
  457.             if (line[0] == '.' && line[1] == '\n') { done = TRUE; break; }
  458.             sscanf(line, "%ld %ld", &index, &size);
  459.             if (index) if (new = calloc(1,sizeof(struct Mail)))
  460.             {
  461.                static int mode2status[16] = { 1,1,3,3,1,1,3,3,0,1,0,3,0,1,0,3 };
  462.                new->Index = index; new->Size = size; new->Folder = NULL;
  463.                mode = (C->DownloadLarge ? 1 : 0) +
  464.                       (C->P3[G->TR->POP_Nr]->DeleteOnServer ? 2 : 0) +
  465.                       (G->TR->GUIlevel == POP_USER ? 4 : 0) +
  466.                       ((C->WarnSize && new->Size >= (C->WarnSize<<10)) ? 8 : 0);
  467.                new->Status = mode2status[mode];
  468.                MyAddTail(&(G->TR->List), new);
  469.             }
  470.          }
  471.          if (done) break;
  472.          if (TR_RecvDat(buf) <= 0) break;
  473.          bufptr = buf;
  474.       }
  475.       return TRUE;
  476.    }
  477.    else return FALSE;
  478. }
  479. ///
  480. /// TR_AppendUIDL
  481. //  Appends a UIDL to the .uidl file
  482. void TR_AppendUIDL(char *uidl)
  483. {
  484.    FILE *fh;
  485.    if (fh = fopen(CreateFilename(".uidl"), "a"))
  486.    {
  487.       fprintf(fh, "%s\n", uidl);
  488.       fclose(fh);
  489.    }
  490. }
  491. ///
  492. /// TR_FindUIDL
  493. //  Searches UIDL list for a given UIDL
  494. BOOL TR_FindUIDL(char *uidl)
  495. {
  496.    int l = strlen(uidl);
  497.    char *p = G->TR->UIDLloc;
  498.    if (p) while (*p)
  499.    {
  500.       if (!strncmp(p, uidl, l)) return TRUE;
  501.       while (*p) if (*p++ == '\n') break;
  502.    }
  503.    return FALSE;
  504. }
  505. ///
  506. /// TR_GetUIDLonDisk
  507. //  Loads local UIDL list from disk
  508. char *TR_GetUIDLonDisk(void)
  509. {
  510.    FILE *fh;
  511.    char *text = NULL, *file = CreateFilename(".uidl");
  512.    int size;
  513.  
  514.    if ((size = FileSize(file)) > 0)
  515.       if (text = calloc(size+1,1))
  516.          if (fh = fopen(file, "r"))
  517.          {
  518.             fread(text, 1, size, fh);
  519.             fclose(fh);
  520.          }
  521.    return text;
  522. }
  523. ///
  524. /// TR_GetUIDLonServer
  525. //  Gets remote UIDL list from the POP3 server
  526. BOOL TR_GetUIDLonServer(void)
  527. {
  528.    char buf[SIZE_LINE];
  529.  
  530.    if (TR_SendPopCmd(buf, "UIDL", NULL, POPCMD_NOERROR))
  531.    {
  532.       int num, l = 0;
  533.       struct Mail *mail;
  534.       char  uidl[SIZE_DEFAULT+SIZE_HOST], line[SIZE_DEFAULT], *bufptr;
  535.       BOOL done = FALSE;
  536.  
  537.       if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  538.       while (!G->Error)
  539.       {
  540.          for (; *bufptr; bufptr++)
  541.          {
  542.             if (*bufptr != '\r') if (l < SIZE_DEFAULT-1) line[l++] = *bufptr;
  543.             if (*bufptr != '\n') continue;
  544.             line[l] = 0; l = 0;
  545.             if (line[0] == '.' && line[1] == '\n') { done = TRUE; break; }
  546.             sscanf(line, "%ld %s", &num, uidl);
  547.             strcat(uidl, "@"); strcat(uidl, C->P3[G->TR->POP_Nr]->Server);
  548.             for (mail = G->TR->List; mail; mail = mail->Next)
  549.                if (mail->Index == num) { mail->UIDL = AllocCopy(uidl, strlen(uidl)+1); break; }
  550.          }
  551.          if (done) break;
  552.          if (TR_RecvDat(buf) <= 0) break;
  553.          bufptr = buf;
  554.       }
  555.       return TRUE;
  556.    }
  557.    else return FALSE;
  558. }
  559. ///
  560. /// TR_ApplyRemoteFilters
  561. //  Applies remote filters to a message
  562. void TR_ApplyRemoteFilters(struct Mail *mail)
  563. {
  564.    int i;
  565.  
  566.    for (i = 0; i < G->TR->Scnt; i++) if (FI_DoComplexSearch(G->TR->Search[i], G->TR->Search[i]->Rule->Combine, G->TR->Search[i+MAXRU], mail))
  567.    {
  568.       struct Rule *rule = G->TR->Search[i]->Rule;
  569.       if (rule->Actions &   8) if (*rule->ExecuteCmd) ExecuteCommand(rule->ExecuteCmd, FALSE, NULL);
  570.       if (rule->Actions &  16) if (*rule->PlaySound) PlaySound(rule->PlaySound);
  571.       if (rule->Actions &  64) mail->Status |= 2; else mail->Status &= ~2;
  572.       if (rule->Actions & 128) mail->Status &= ~1; else mail->Status |= 1;
  573.       return;
  574.    }
  575. }
  576. ///
  577. /// TR_GetMessageDetails
  578. //  Gets header from a message stored on the POP3 server
  579. void TR_GetMessageDetails(struct Mail *mail, int lline)
  580. {
  581.    if (!*mail->From.Address)
  582.    {
  583.       char buf[SIZE_LINE], cmdbuf[SIZE_SMALL], *tfname = "yamTOP.tmp";
  584.       sprintf(cmdbuf, "%ld 1", mail->Index);
  585.       if (TR_SendPopCmd(buf, "TOP", cmdbuf, POPCMD_NOERROR))
  586.       {
  587.          char fname[SIZE_PATHFILE];
  588.          FILE *f;
  589.          strmfp(fname, C->TempDir, tfname);
  590.          if (f = fopen(fname, "w"))
  591.          {
  592.             struct ExtendedMail *email;
  593.             int l = 0;
  594.             char line[SIZE_LINE], *bufptr;
  595.             BOOL done = FALSE;
  596.  
  597.             if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  598.             while (!G->Error && !G->TR->Abort)
  599.             {
  600.                for (; *bufptr; bufptr++)
  601.                {
  602.                   if (*bufptr != '\r') line[l++] = *bufptr;
  603.                   if (l == SIZE_LINE-1)
  604.                   {
  605.                      line[l] = 0; l = 0;
  606.                      if (fputs(line, f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), fname, NULL); break; }
  607.                   }
  608.                   if (*bufptr != '\n') continue;
  609.                   line[l] = 0; l = 0;
  610.                   if (line[0] == '.') if (line[1] == '\n') { done = TRUE; break; }
  611.                   if (fputs(line, f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), fname, NULL); break; }
  612.                }
  613.                if (done) break;
  614.                if (TR_RecvDat(buf) <= 0) break;
  615.                bufptr = buf;
  616.             }
  617.             fclose(f);
  618.             if (email = MA_ExamineMail(NULL, tfname, NULL, TRUE))
  619.             {
  620.                mail->From    = email->Mail.From;
  621.                mail->To      = email->Mail.To;
  622.                mail->ReplyTo = email->Mail.ReplyTo;
  623.                strcpy(mail->Subject, email->Mail.Subject);
  624.                strcpy(mail->MailFile, email->Mail.MailFile);
  625.                mail->Date = email->Mail.Date;
  626.                if (lline == -1)
  627.                {
  628.                   char uidl[SIZE_DEFAULT+SIZE_HOST];
  629.                   sprintf(uidl, "%s@%s", Trim(email->MsgID), C->P3[G->TR->POP_Nr]->Server);
  630.                   mail->UIDL = AllocCopy(uidl, strlen(uidl)+1);
  631.                }
  632.                if (lline == -2) TR_ApplyRemoteFilters(mail);
  633.                DeleteFile(fname);
  634.                MA_FreeEMailStruct(email);
  635.             }
  636.          }
  637.          else ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), fname, NULL);
  638.       }
  639.    }
  640.    if (lline >= 0) DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Redraw, lline);
  641. }
  642. ///
  643. /// TR_GetUIDL
  644. //  Filters out duplicate messages
  645. void TR_GetUIDL(void)
  646. {
  647.    struct Mail *mail;
  648.    G->TR->supportUIDL = TR_GetUIDLonServer();
  649.    G->TR->UIDLloc = TR_GetUIDLonDisk();
  650.    for (mail = G->TR->List; mail; mail = mail->Next)
  651.    {
  652.       if (!G->TR->supportUIDL) TR_GetMessageDetails(mail, -1);
  653.       if (TR_FindUIDL(mail->UIDL)) { G->TR->Stats.DupSkipped++; mail->Status &= 2; }
  654.    }
  655. }
  656. ///
  657. /// TR_DisconnectPOP
  658. //  Terminates a POP3 session
  659. void TR_DisconnectPOP(void)
  660. {
  661.    char buf[SIZE_LINE];
  662.  
  663.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_Disconnecting));
  664.    if (!G->TR->Abort) TR_SendPopCmd(buf, "QUIT", NULL, POPCMD_WAITEOL);
  665.    TR_Disconnect();
  666. }
  667. ///
  668. /// TR_GetMailFromNextPOP
  669. //  Downloads and filters mail from a POP3 account
  670. void TR_GetMailFromNextPOP(BOOL isfirst, int singlepop, int guilevel)
  671. {
  672.    extern void SAVEDS TR_ProcessGETFunc(void);
  673.    struct Mail *mail;
  674.    static int laststats;
  675.    int msgs, pop = singlepop;
  676.  
  677.    if (isfirst) /* Init first connection */
  678.    {
  679.       G->LastDL.Error = TRUE;
  680.       if (!TR_OpenTCPIP()) { if (guilevel == POP_USER) ER_NewError(GetStr(MSG_ER_NoTCP), NULL, NULL); return; }
  681.       if (!CO_IsValid()) { TR_CloseTCPIP(); return; }
  682.       if (!(G->TR = TR_New(TR_GET))) { TR_CloseTCPIP(); return; }
  683.       G->TR->Checking = TRUE; DisplayStatistics((struct Folder *)-1);
  684.       G->TR->GUIlevel = guilevel;
  685.       G->TR->Scnt = MA_AllocRules(G->TR->Search, APPLY_REMOTE);
  686.       if (singlepop >= 0) G->TR->SinglePOP = TRUE;
  687.       else G->TR->POP_Nr = -1;
  688.       laststats = 0;
  689.    }
  690.    else /* Finish previous connection */
  691.    {
  692.       struct POP3 *p = C->P3[G->TR->POP_Nr];
  693.       TR_DisconnectPOP();
  694.       TR_Cleanup();
  695.       AppendLogNormal(30, GetStr(MSG_LOG_Retrieving), (void *)(G->TR->Stats.Downloaded-laststats), p->User, p->Server, "");
  696.       if (G->TR->SinglePOP) pop = MAXP3;
  697.       laststats = G->TR->Stats.Downloaded;
  698.    }
  699.    if (!G->TR->SinglePOP) for (pop = ++G->TR->POP_Nr; pop < MAXP3; pop++)
  700.                              if (C->P3[pop]) if (C->P3[pop]->Enabled) break;
  701.    if (pop == MAXP3) /* Finish last connection */
  702.    {
  703.       TR_CloseTCPIP();
  704.       set(G->TR->GUI.WI, MUIA_Window_Open, FALSE);
  705.       MA_FreeRules(G->TR->Search, G->TR->Scnt);
  706.       MA_StartMacro(MACRO_POSTGET, itoa(G->TR->Stats.Downloaded));
  707.       DoMethod(G->App, MUIM_CallHook, &MA_ApplyRulesHook, APPLY_AUTO, 0, FALSE);
  708.       G->TR->Checking = FALSE; DisplayStatistics((struct Folder *)-1);
  709.       TR_NewMailAlert();
  710.       MA_ChangeTransfer(TRUE);
  711.       DisposeModulePush(&G->TR);
  712.       if (G->TR_Exchange)
  713.       {
  714.          G->TR_Exchange = FALSE;
  715.          DoMethod(G->App, MUIM_Application_PushMethod, G->App, 3, MUIM_CallHook, &MA_SendHook, SEND_ALL);
  716.       }
  717.       return;
  718.    }
  719.    G->TR->POP_Nr = pop;
  720.    G->TR_Allow = G->TR->Abort = G->Error = FALSE;
  721.    if ((msgs = TR_ConnectPOP(G->TR->GUIlevel)) != -1)        // connection succeeded
  722.    {
  723.       if (msgs)                                                        // there are messages on the server
  724.       {
  725.          if (TR_GetMessageList_GET(msgs))                        // message list read OK
  726.          {
  727.             BOOL preselect = FALSE;
  728.             G->TR->Stats.OnServer += msgs;
  729.             if (G->TR->Scnt)                                        // filter messages on server?
  730.             {
  731.                set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_ApplyFilters));
  732.                for (mail = G->TR->List; mail; mail = mail->Next)
  733.                   TR_GetMessageDetails(mail, -2);
  734.             }
  735.             if (C->AvoidDuplicates) TR_GetUIDL();            // read UIDL file to compare against already received messages
  736.             if (G->TR->GUIlevel == POP_USER)                    // manually initiated transfer
  737.             {
  738.                if (C->PreSelection >= 2) preselect = TRUE;                // preselect messages if preference is "always [sizes only]"
  739.                if (C->WarnSize && C->PreSelection)                            // ...or any sort of preselection and there is a maximum size
  740.                   for (mail = G->TR->List; mail; mail = mail->Next)    // ...and one of the messages is at least this big
  741.                      if (mail->Size >= C->WarnSize<<10) { preselect = TRUE; break; }
  742.             }
  743.             if (preselect)                                                // anything to preselect?
  744.             {
  745.                set(G->TR->GUI.WI, MUIA_Window_Open, TRUE);
  746.                if (C->PreSelection == 1)
  747.                {
  748.                   TR_DisplayMailList(TRUE);                                        // add entries to list
  749.                   set(G->TR->GUI.GR_LIST, MUIA_ShowMe, TRUE);                // ...and show it
  750.                   set(G->TR->GUI.WI, MUIA_Window_Activate, TRUE);            // activate window
  751.                   DoMethod(G->TR->GUI.WI, MUIM_Window_ScreenToFront);
  752.                }
  753.                else TR_DisplayMailList(FALSE);
  754.                set(G->TR->GUI.GR_PAGE, MUIA_Group_ActivePage, 0);
  755.                G->TR->GMD_Mail = G->TR->List;
  756.                G->TR->GMD_Line = 0;
  757.                TR_CompleteMsgList();
  758.                return;
  759.             }
  760.             else
  761.             {
  762.                TR_ProcessGETFunc();
  763.             }
  764.             return;
  765.          }
  766.       }
  767.    }
  768.    else G->TR->Stats.Error = TRUE;
  769.    TR_GetMailFromNextPOP(FALSE, 0, 0);
  770. }
  771. ///
  772.  
  773. /*** SMTP routines ***/
  774. /// TR_SendSMTPCmd
  775. //  Sends a command to the SMTP server
  776. BOOL TR_SendSMTPCmd(char *cmdtext, char *parmtext)
  777. {
  778.    int len;
  779.    static char buffer[SIZE_LINE];
  780.    char cont;
  781.  
  782.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  783.    if (cmdtext) 
  784.    {
  785.       sprintf(buffer, "%s\r\n", cmdtext);
  786.       if (parmtext) if (*parmtext) sprintf(buffer, "%s %s\r\n", cmdtext, parmtext);
  787.    }
  788.    else *buffer = 0;
  789.    if (!TR_SendDat(buffer)) return FALSE;
  790.    if ((len = TR_RecvDat(buffer)) <= 0) return FALSE;
  791.    switch (atoi(buffer))
  792.    {
  793.       case 211: case 214: case 220: case 221: 
  794.       case 250: case 251: case 354: break;
  795.       default:  ER_NewError(GetStr(MSG_ER_BadResponse), cmdtext, buffer); return FALSE;
  796.    }
  797.    cont = buffer[3];
  798.    while (buffer[len-1] != '\n') if ((len = TR_RecvDat(buffer)) <= 0) return FALSE;
  799.    if (cont == '-') while (buffer[len-1] != '\n') if ((len = TR_RecvDat(buffer)) <= 0) break;
  800.    return TRUE;
  801. }
  802. ///
  803. /// TR_ConnectSMTP
  804. //  Connects to a SMTP mail server
  805. BOOL TR_ConnectSMTP(void)
  806. {
  807.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_WaitWelcome));
  808.    if (!TR_SendSMTPCmd(NULL, NULL)) return FALSE;
  809.    set(G->TR->GUI.TX_STATUS,MUIA_Text_Contents, GetStr(MSG_TR_SendHello));
  810.    if (!TR_SendSMTPCmd("HELO", C->SMTP_Domain)) return FALSE;
  811.    return TRUE;
  812. }
  813. ///
  814. /// TR_ConnectESMTP
  815. //  Connects to a ESMTP mail server, checks some ESMTP features and sends SMTP AUTH
  816. /* umsrfc ReadLine() */
  817. /*
  818.  * Read one line from client. The buffer may hold a maximum of "len"
  819.  * characters including string terminator. The routine returns FALSE
  820.  * when the connection to the client was lost during reading the line.
  821.  * The buffer will always contain a valid C string after the call.
  822. .*/
  823. static BOOL ReadLine(LONG Socket, char *buf, LONG len)
  824. {
  825.  char *p = buf;
  826.  
  827.    DoMethod(G->App,MUIM_Application_InputBuffered);
  828.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  829.  /* Is enough space left in buffer to read more characters? */
  830.  while (--len > 0) {
  831.  
  832.   /* Yes, read one character from socket */
  833.   if (Recv(Socket, p, 1, 0) <= 0) {
  834.  
  835.    /* Error or end of input reached */
  836.    len = -1;
  837.  
  838.    /* Leave loop */
  839.    break;
  840.   }
  841.  
  842.   /* End of line reached? */
  843.   if (*p == '\n') {
  844.  
  845.    /* Yes, strip CR if line end was marked by CRLF */
  846.    if ((p != buf) && (*(p - 1) == '\r')) p--;
  847.  
  848.    /* Leave loop */
  849.    break;
  850.  
  851.   } else
  852.    /* No, normal character */
  853.    p++;
  854.  }
  855.  
  856.  /* Add string terminator */
  857.  *p = '\0';
  858.  
  859.    if (G->TR_Debug) printf("SERVER: %s\n", buf);
  860.  return (BOOL)(len >= 0);
  861. }
  862. #define SMTP_SERVICE_NOT_AVAILABLE 421
  863. #define SMTP_ACTION_OK             250
  864. /* Read answer from server */
  865. static ULONG GetReturnCode(void)
  866. {
  867.  ULONG rc;
  868.  char *p;
  869.    char buffer[SIZE_LINE];
  870.  
  871.  /* Read multiple lines from server */
  872.  do {
  873.  
  874.   /* Read line from server */
  875.   if (ReadLine(G->TR_Socket, buffer, SIZE_LINE)) {
  876.  
  877.    /* Convert number */
  878.    rc = strtol(buffer, &p, 10);
  879.  
  880.   } else {
  881.    /* Error! */
  882.    rc = SMTP_SERVICE_NOT_AVAILABLE;
  883.  
  884.    /* Leave loop */
  885.    break;
  886.   }
  887.  
  888.   /* Multiple line reply? */
  889.  } while (*p != ' ');
  890.  
  891.  return(rc);
  892. }
  893.  
  894. #define AUTH_CRAM_MD5   1
  895. #define AUTH_DIGEST_MD5 2
  896. #define AUTH_LOGIN      4
  897. #define AUTH_PLAIN      8
  898. void hmac_md5(unsigned char*,int,unsigned char*,int,ULONG *);
  899. void encode64(char *s, char *d, int len);
  900. char *decode64 (char *dest, char *src, char *srcmax);
  901. BOOL TR_ConnectESMTP(void)
  902. {
  903.    int len,rc;
  904.    char buffer[SIZE_LINE];
  905.    char challenge[SIZE_LINE];
  906.    UBYTE ESMTPAuth=0;
  907.    int SMTPSocket=G->TR_Socket;
  908.  
  909.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_WaitWelcome));
  910.    if (!TR_SendSMTPCmd(NULL, NULL)) return FALSE;
  911.    set(G->TR->GUI.TX_STATUS,MUIA_Text_Contents, GetStr(MSG_TR_SendHello));
  912.  
  913.    if (G->TR_Socket == SMTP_NO_SOCKET) return FALSE;
  914.    sprintf(buffer, "EHLO %s\r\n", C->SMTP_Domain);
  915.    if (!TR_SendDat(buffer)) return FALSE;
  916.    if(!(ReadLine(SMTPSocket, buffer, SIZE_LINE))) return FALSE;
  917.    if(SMTP_ACTION_OK!=atoi(buffer))
  918.    {
  919.       ER_NewError(GetStr(MSG_ER_BadResponse), "EHLO", buffer);
  920.       return FALSE;
  921.    }
  922.    while (buffer[3] == '-')
  923.    {
  924.       if(!(ReadLine(SMTPSocket, buffer, SIZE_LINE))) return FALSE;
  925.       if (strnicmp(buffer+4, "AUTH", 4) == 0) /* SMTP AUTH */
  926.       {
  927.          if (NULL != strstr(buffer+9,"CRAM-MD5")) ESMTPAuth|=AUTH_CRAM_MD5;
  928.          if (NULL != strstr(buffer+9,"DIGEST-MD5")) ESMTPAuth|=AUTH_DIGEST_MD5;
  929.          if (NULL != strstr(buffer+9,"PLAIN")) ESMTPAuth|=AUTH_PLAIN;
  930.          if (NULL != strstr(buffer+9,"LOGIN")) ESMTPAuth|=AUTH_LOGIN;
  931.       }
  932.    }
  933.  
  934.    if(0==ESMTPAuth)
  935.    {
  936.       ER_NewError(GetStr(MSG_ER_NO_SMTP_AUTH), C->SMTP_Server, NULL);
  937.       return FALSE;
  938.    }
  939.  
  940.    if(ESMTPAuth & AUTH_CRAM_MD5) /* js_umsrfc SMTP AUTH */
  941.    {
  942.       /* Send AUTH command */
  943.       if(!(TR_SendDat("AUTH CRAM-MD5\r\n"))) return FALSE;
  944.   
  945.       if (ReadLine(SMTPSocket, buffer, SIZE_LINE))
  946.       {
  947.          char *p;
  948.   
  949.          /* Get return code. */
  950.          if ((rc=strtol(buffer, &p, 10)) == 334 )
  951.          {
  952.             ULONG digest[4];
  953.   
  954.             strncpy(challenge,p+1,511); challenge[511]=0;
  955.             decode64(challenge,challenge,challenge+strlen(challenge));
  956.   
  957.             hmac_md5(challenge,strlen(challenge),C->SMTP_AUTH_Pass,strlen(C->SMTP_AUTH_Pass),digest);
  958.   
  959.             len=sprintf(challenge,"%s %08lx%08lx%08lx%08lx%c%c",C->SMTP_AUTH_User,
  960.                         digest[0],digest[1],digest[2],digest[3],0,0)-2;
  961.             encode64(challenge,buffer,len);
  962.             strcat(buffer,"\r\n");
  963.   
  964.             /* Send AUTH response */
  965.             if(!(TR_SendDat(buffer))) return FALSE;
  966.  
  967.             if (ReadLine(SMTPSocket, buffer, SIZE_LINE))
  968.             {
  969.                /* Get return code. */
  970.                if ((rc=strtol(buffer, &p, 10)) != 235 )
  971.                {
  972.                   ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH CRAM-MD5", buffer);
  973.                   rc = SMTP_SERVICE_NOT_AVAILABLE;
  974.                } else rc = SMTP_ACTION_OK;
  975.             } else rc = SMTP_SERVICE_NOT_AVAILABLE;
  976.          } else {
  977.             ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH CRAM-MD5", buffer);
  978.             rc = SMTP_SERVICE_NOT_AVAILABLE;
  979.          }
  980.       } else rc = SMTP_SERVICE_NOT_AVAILABLE;
  981.    } else if(ESMTPAuth & AUTH_DIGEST_MD5)
  982.    {
  983.       /* Send AUTH command */
  984.       if(!(TR_SendDat("AUTH DIGEST-MD5\r\n"))) return FALSE;
  985.   
  986.       if (ReadLine(SMTPSocket, buffer, SIZE_LINE))
  987.       {
  988.          char *p;
  989.   
  990.          /* Get return code. */
  991.          if ((rc=strtol(buffer, &p, 10)) == 334 )
  992.          {
  993.             ULONG digest[4];
  994.             MD5_CTX context;
  995.   
  996.             strncpy(challenge,p+1,511); challenge[511]=0;
  997.             decode64(challenge,challenge,challenge+strlen(challenge));
  998.   
  999.             strcat(challenge,C->SMTP_AUTH_Pass);
  1000.             MD5Init(&context);
  1001.             MD5Update(&context, challenge, strlen(challenge));
  1002.             MD5Final((UBYTE *)digest, &context);
  1003.  
  1004.             len=sprintf(challenge,"%s %08lx%08lx%08lx%08lx%c%c",C->SMTP_AUTH_User,
  1005.                         digest[0],digest[1],digest[2],digest[3],0,0)-2;
  1006.             encode64(challenge,buffer,len);
  1007.             strcat(buffer,"\r\n");
  1008.   
  1009.             /* Send AUTH response */
  1010.             if(!(TR_SendDat(buffer))) return FALSE;
  1011.   
  1012.             if (ReadLine(SMTPSocket, buffer, SIZE_LINE))
  1013.             {
  1014.                /* Get return code. */
  1015.                if ((rc=strtol(buffer, &p, 10)) != 235 )
  1016.                {
  1017.                   ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH DIGEST-MD5", buffer);
  1018.                   rc = SMTP_SERVICE_NOT_AVAILABLE;
  1019.                } else rc = SMTP_ACTION_OK;
  1020.             } else rc = SMTP_SERVICE_NOT_AVAILABLE;
  1021.          } else {
  1022.             ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH DIGEST-MD5", buffer);
  1023.             rc = SMTP_SERVICE_NOT_AVAILABLE;
  1024.          }
  1025.       } else rc = SMTP_SERVICE_NOT_AVAILABLE;
  1026.    } else if(ESMTPAuth & AUTH_LOGIN)
  1027.    {
  1028.       /* Send AUTH command */
  1029.       if(!(TR_SendDat("AUTH LOGIN\r\n"))) return FALSE;
  1030.       /* Get return code */
  1031.       rc = GetReturnCode();
  1032.   
  1033.       if (rc == 334)
  1034.       {
  1035.          len=sprintf(challenge,"%s%c%c",C->SMTP_AUTH_User,0,0)-2;
  1036.          encode64(challenge,buffer,len);
  1037.          strcat(buffer,"\r\n");
  1038.          /* Send AUTH response Username: */
  1039.          if(!(TR_SendDat(buffer))) return FALSE;
  1040.          /* Get return code */
  1041.          rc = GetReturnCode();
  1042.          if (rc == 334)
  1043.          {
  1044.             len=sprintf(challenge,"%s%c%c",C->SMTP_AUTH_Pass,0,0)-2;
  1045.             encode64(challenge,buffer,len);
  1046.             strcat(buffer,"\r\n");
  1047.             /* Send AUTH response Password: */
  1048.             if(!(TR_SendDat(buffer))) return FALSE;
  1049.             /* Get return code */
  1050.             rc = GetReturnCode();
  1051.             if (rc != 235 )
  1052.             {
  1053.                ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH LOGIN", buffer);
  1054.                rc = SMTP_SERVICE_NOT_AVAILABLE;
  1055.             } else rc = SMTP_ACTION_OK;
  1056.          } else {
  1057.             ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH LOGIN", buffer);
  1058.             rc = SMTP_SERVICE_NOT_AVAILABLE;
  1059.          }
  1060.       } else {
  1061.          ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH LOGIN", buffer);
  1062.          rc = SMTP_SERVICE_NOT_AVAILABLE;
  1063.       }
  1064.    } else if(ESMTPAuth & AUTH_PLAIN)
  1065.    {
  1066.       /* Send AUTH command */
  1067.       if(!(TR_SendDat("AUTH PLAIN\r\n"))) return FALSE;
  1068.       /* Get return code */
  1069.       rc = GetReturnCode();
  1070.   
  1071.       if (rc == 334)
  1072.       {
  1073.          len=0;
  1074.          challenge[len++]=0;
  1075.          len+=sprintf(challenge+len,"%s",C->SMTP_AUTH_User);
  1076.          len++;
  1077.          len+=sprintf(challenge+len,"%s",C->SMTP_AUTH_Pass);
  1078.          encode64(challenge,buffer,len);
  1079.          strcat(buffer,"\r\n");
  1080.          /* Send AUTH response */
  1081.          if(!(TR_SendDat(buffer))) return FALSE;
  1082.          /* Get return code */
  1083.          rc = GetReturnCode();
  1084.   
  1085.          if (rc != 235 )
  1086.          {
  1087.             ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH LOGIN", buffer);
  1088.             rc = SMTP_SERVICE_NOT_AVAILABLE;
  1089.          } else rc = SMTP_ACTION_OK;
  1090.       } else {
  1091.          ER_NewError(GetStr(MSG_ER_BadResponse), "AUTH LOGIN", buffer);
  1092.          rc = SMTP_SERVICE_NOT_AVAILABLE;
  1093.       }
  1094.    }
  1095.  
  1096.    if(SMTP_ACTION_OK==rc) return TRUE;
  1097.    return FALSE;
  1098. }
  1099. ///
  1100. /// TR_DisconnectSMTP
  1101. //  Terminates a SMTP session
  1102. void TR_DisconnectSMTP(void)
  1103. {
  1104.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_Disconnecting));
  1105.    if (!G->TR->Abort) TR_SendSMTPCmd("QUIT", NULL);
  1106.    TR_Disconnect();
  1107. }
  1108. ///
  1109. /// TR_ChangeStatusFunc
  1110. //  Changes status of selected messages
  1111. void SAVEDS ASM TR_ChangeStatusFunc(REG(a1,int *arg))
  1112. {
  1113.    int id = MUIV_NList_NextSelected_Start;
  1114.    struct Mail *mail;
  1115.    for (;;)
  1116.    {
  1117.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_NextSelected, &id);
  1118.       if (id == MUIV_NList_NextSelected_End) break;
  1119.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_GetEntry, id, &mail);
  1120.       mail->Status = *arg;
  1121.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Redraw, id);
  1122.    }
  1123. }
  1124. MakeHook(TR_ChangeStatusHook, TR_ChangeStatusFunc);
  1125. ///
  1126. /// TR_GetSeconds
  1127. //  Gets current date and time in seconds
  1128. long TR_GetSeconds(void)
  1129. {
  1130.    struct DateStamp ds;
  1131.    DateStamp(&ds);
  1132.    return ((86400*ds.ds_Days) + (60*ds.ds_Minute) + (ds.ds_Tick/50));
  1133. }
  1134. ///
  1135. /// TR_TransStat_Init
  1136. //  Initializes transfer statistics
  1137. void TR_TransStat_Init(struct TransStat *ts)
  1138. {
  1139.    struct Mail *mail;
  1140.  
  1141.    ts->Msgs_Tot = ts->Size_Tot = 0;
  1142.    if (G->TR->GUI.GR_LIST)
  1143.    {
  1144.       set(G->TR->GUI.GR_PAGE, MUIA_Group_ActivePage, 1);
  1145.       DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Off, NULL);
  1146.    }
  1147.    for (mail = G->TR->List; mail; mail = mail->Next)
  1148.    {
  1149.       ts->Msgs_Tot++;
  1150.       if (mail->Status & 1) ts->Size_Tot += mail->Size;
  1151.    }
  1152. }
  1153. ///
  1154. /// TR_TransStat_Start
  1155. //  Resets statistics display
  1156. void TR_TransStat_Start(struct TransStat *ts)
  1157. {
  1158.    ts->Msgs_Done = ts->Size_Done = 0;
  1159.    SPrintF(G->TR->CountLabel, GetStr(MSG_TR_MessageGauge), "%ld", ts->Msgs_Tot);
  1160.    set(G->TR->GUI.GA_COUNT, MUIA_Gauge_InfoText, G->TR->CountLabel);
  1161.    set(G->TR->GUI.GA_COUNT, MUIA_Gauge_Max, ts->Msgs_Tot);
  1162.    ts->Clock_Start = TR_GetSeconds();
  1163. }
  1164. ///
  1165. /// TR_TransStat_NextMsg
  1166. //  Updates statistics display for next message
  1167. void TR_TransStat_NextMsg(struct TransStat *ts, int index, int listpos, int size, char *status)
  1168. {
  1169.    ts->Size_Curr = 0;
  1170.    ts->Clock_Last = 0;
  1171.    ts->Delay = 0;
  1172.    if (!GetMUI(G->TR->GUI.WI, MUIA_Window_Open)) return;
  1173.    else if (size <    2500) ts->Delay = 256;
  1174.    else if (size <   25000) ts->Delay = 512;
  1175.    else if (size <  250000) ts->Delay = 1024;
  1176.    else if (size < 2500000) ts->Delay = 2048;
  1177.    else                     ts->Delay = 4096;
  1178.    if (G->TR->GUI.GR_LIST && listpos >= 0) set(G->TR->GUI.LV_MAILS, MUIA_NList_Active, listpos);
  1179.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, status);
  1180.    set(G->TR->GUI.GA_COUNT, MUIA_Gauge_Current, index);
  1181.    SPrintF(G->TR->BytesLabel, GetStr(MSG_TR_SizeGauge), size);
  1182.    set(G->TR->GUI.GA_BYTES, MUIA_Gauge_InfoText, G->TR->BytesLabel);
  1183.    set(G->TR->GUI.GA_BYTES, MUIA_Gauge_Max, size);
  1184. }
  1185. ///
  1186. /// TR_TransStat_Update
  1187. //  Updates statistics display for next block of data
  1188. void TR_TransStat_Update(struct TransStat *ts, int size_incr)
  1189. {
  1190.    long clock;
  1191.    int speed = 0, remclock = 0;
  1192.    static long size_done = 0;
  1193.  
  1194.    if (!ts->Size_Done) size_done = 0;
  1195.    ts->Size_Curr += size_incr;
  1196.    ts->Size_Done += size_incr;
  1197.    if (!ts->Delay) return;
  1198.    if (ts->Size_Done-size_done > ts->Delay)
  1199.    {
  1200.       set(G->TR->GUI.GA_BYTES, MUIA_Gauge_Current, ts->Size_Curr);
  1201.       DoMethod(G->App, MUIM_Application_InputBuffered);
  1202.       size_done = ts->Size_Done;
  1203.    }
  1204.    if ((clock = (TR_GetSeconds()-ts->Clock_Start)) == ts->Clock_Last) return;
  1205.    ts->Clock_Last = clock;
  1206.    if (clock) speed = ts->Size_Done/clock;
  1207.    if (speed) remclock = MAX(ts->Size_Tot/speed-clock,0);
  1208.    SPrintF(G->TR->StatsLabel, GetStr(MSG_TR_TransferStats),
  1209.       ts->Size_Done>>10, ts->Size_Tot>>10, speed, remclock/60, remclock%60);
  1210.    set(G->TR->GUI.TX_STATS, MUIA_Text_Contents, G->TR->StatsLabel);
  1211. }
  1212. ///
  1213. /// TR_Cleanup
  1214. //  Free temporary message and UIDL lists
  1215. void TR_Cleanup(void)
  1216. {
  1217.    struct Mail *work, *next;
  1218.  
  1219.    if (G->TR->GUI.LV_MAILS) DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_Clear);
  1220.    for (work = G->TR->List; work; work = next)
  1221.    {
  1222.       next = work->Next;
  1223.       if (work->UIDL) free(work->UIDL);
  1224.       free(work);
  1225.    }
  1226.    if (G->TR->UIDLloc) free(G->TR->UIDLloc);
  1227.    G->TR->UIDLloc = NULL;
  1228.    G->TR->List = NULL;
  1229. }
  1230. ///
  1231. /// TR_AbortnClose
  1232. //  Aborts a transfer
  1233. void TR_AbortnClose(void)
  1234. {
  1235.    set(G->TR->GUI.WI, MUIA_Window_Open, FALSE);
  1236.    TR_Cleanup();
  1237.    MA_ChangeTransfer(TRUE);
  1238.    DisposeModulePush(&G->TR);
  1239. }
  1240. ///
  1241. /// TR_ApplySentFilters
  1242. //  Applies filters to a sent message
  1243. BOOL TR_ApplySentFilters(struct Mail *mail)
  1244. {
  1245.    int i;
  1246.    for (i = 0; i < G->TR->Scnt; i++)
  1247.       if (FI_DoComplexSearch(G->TR->Search[i], G->TR->Search[i]->Rule->Combine, G->TR->Search[i+MAXRU], mail))
  1248.          if (!MA_ExecuteRuleAction(G->TR->Search[i]->Rule, mail)) return FALSE;
  1249.    return TRUE;
  1250. }
  1251. ///
  1252.  
  1253. /*** EXPORT ***/
  1254. /// TR_ProcessEXPORT
  1255. //  Saves a list of messages to a UUCP mailbox file
  1256. BOOL TR_ProcessEXPORT(char *fname, struct Mail **mlist, BOOL append)
  1257. {
  1258.    BOOL success = FALSE;
  1259.    struct TransStat ts;
  1260.    int i, c;
  1261.    char buf[SIZE_LINE], fullfile[SIZE_PATHFILE];
  1262.    FILE *fh, *mfh;
  1263.    struct Mail *mail, *new;
  1264.  
  1265.    G->TR->List = NULL;
  1266.    for (c = i = 0; i < (int)*mlist; i++)
  1267.    {
  1268.       if (new = calloc(1,sizeof(struct Mail)))
  1269.       {
  1270.          *new = *mlist[i+2];
  1271.          new->Index = ++c; new->Status = 1;
  1272.          MyAddTail(&(G->TR->List), new);
  1273.       }
  1274.    }
  1275.    if (c)
  1276.    {
  1277.       TR_SetWinTitle(FALSE, FilePart(fname));
  1278.       TR_TransStat_Init(&ts);
  1279.       TR_TransStat_Start(&ts);
  1280.       if (fh = fopen(fname, append ? "a" : "w"))
  1281.       {
  1282.          success = TRUE;
  1283.          for (mail = G->TR->List; mail && !G->TR->Abort; mail = mail->Next)
  1284.          {
  1285.             ts.Msgs_Done++;
  1286.             TR_TransStat_NextMsg(&ts, mail->Index, -1, mail->Size, GetStr(MSG_TR_Exporting));
  1287.             if (StartUnpack(GetMailFile(NULL, NULL, mail), fullfile, mail->Folder))
  1288.             {
  1289.                if (mfh = fopen(fullfile, "r"))
  1290.                {
  1291.                   fprintf(fh, "From %s %s", mail->From.Address, DateStamp2String(&mail->Date, DSS_UNIXDATE));
  1292.                   while (fgets(buf, SIZE_LINE, mfh) && !G->TR->Abort)
  1293.                   {
  1294.                      if (!strncmp(buf, "From ", 5)) fputc('>', fh);
  1295.                      fputs(buf, fh);
  1296.                      TR_TransStat_Update(&ts, strlen(buf));
  1297.                   }
  1298.                   if (*buf) if (buf[strlen(buf)-1] != '\n') fputc('\n', fh);
  1299.                   fclose(mfh);
  1300.                }
  1301.                FinishUnpack(fullfile);
  1302.             }
  1303.          }
  1304.       }
  1305.       fclose(fh);
  1306.       AppendLog(51, GetStr(MSG_LOG_Exporting), (void *)ts.Msgs_Done, G->TR->List->Folder->Name, fname, "");
  1307.    }
  1308.    TR_AbortnClose();
  1309.    return success;
  1310. }
  1311. ///
  1312.  
  1313. /*** SEND ***/
  1314. /// TR_SendMessage
  1315. //  Sends a single message
  1316. int TR_SendMessage(struct TransStat *ts, struct Mail *mail)
  1317. {
  1318.    int result = 0;
  1319.    struct Folder *outfolder = FO_GetFolderByType(FT_OUTGOING, NULL);
  1320.    char *mf;
  1321.    FILE *f;
  1322.  
  1323.    if (f = fopen(mf = GetMailFile(NULL, outfolder, mail), "r"))
  1324.    {
  1325.       char buf[SIZE_LINE];
  1326.       sprintf(buf, "FROM:<%s>", C->EmailAddress);
  1327.       if (TR_SendSMTPCmd("MAIL", buf))
  1328.       {
  1329.          int j;
  1330.          BOOL rcptok = TRUE;
  1331.          struct ExtendedMail *email = MA_ExamineMail(outfolder, mail->MailFile, NULL, TRUE);
  1332.          sprintf(buf, "TO:<%s>", mail->To.Address);
  1333.          if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1334.          for (j = 0; j < email->NoSTo && rcptok; j++)
  1335.          {
  1336.             sprintf(buf, "TO:<%s>", email->STo[j].Address);
  1337.             if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1338.          }
  1339.          for (j = 0; j < email->NoCC && rcptok; j++)
  1340.          {
  1341.             sprintf(buf, "TO:<%s>", email->CC[j].Address);
  1342.             if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1343.          }
  1344.          for (j = 0; j < email->NoBCC && rcptok; j++)
  1345.          {
  1346.             sprintf(buf, "TO:<%s>", email->BCC[j].Address);
  1347.             if (!TR_SendSMTPCmd("RCPT", buf)) rcptok = FALSE;
  1348.          }
  1349.          if (rcptok)
  1350.          {
  1351.             if (TR_SendSMTPCmd("DATA", NULL)) 
  1352.             {
  1353.                BOOL infield = FALSE, inbody = FALSE;
  1354.                while (fgets(buf, SIZE_LINE-1, f) && !G->TR->Abort && !G->Error)
  1355.                {
  1356.                   char *p, sendbuf[SIZE_LINE+2];
  1357.                   int sb = strlen(buf);
  1358.                   if (p = strpbrk(buf, "\r\n")) *p = 0;
  1359.                   if (!*buf && !inbody)
  1360.                   {
  1361.                      inbody = TRUE; infield = FALSE;
  1362.                   }
  1363.                   if (!ISpace(*buf) && !inbody) infield = !strnicmp(buf, "bcc", 3) || !strnicmp(buf, "x-yam-", 6);
  1364.                   if (!infield)
  1365.                   {
  1366.                      *sendbuf = 0;
  1367.                      if (*buf == '.') strcat(sendbuf, "."); /* RFC 821 */
  1368.                      strcat(sendbuf, buf);
  1369.                      strcat(sendbuf, "\r\n");
  1370.                      if (!TR_SendDat(sendbuf)) ER_NewError(GetStr(MSG_ER_ConnectionBroken), NULL, NULL);
  1371.                   }
  1372.                   TR_TransStat_Update(ts, sb);
  1373.                }
  1374.                if (_OSERR) ER_NewError(GetStr(MSG_ER_ErrorReadMailfile), mf, NULL);
  1375.                else if (!G->TR->Abort && !G->Error)
  1376.                {
  1377.                   result = email->DelSend ? 2 : 1;
  1378.                   AppendLogVerbose(41, GetStr(MSG_LOG_SendingVerbose), AddrName(mail->To), mail->Subject, (void *)mail->Size, "");
  1379.                }
  1380.                TR_SendSMTPCmd("\r\n.", NULL);
  1381.             }
  1382.          }
  1383.          else ER_NewError(GetStr(MSG_ER_InvalidAddress), buf, NULL);
  1384.          MA_FreeEMailStruct(email);
  1385.       }
  1386.       fclose(f);
  1387.    }
  1388.    else ER_NewError(GetStr(MSG_ER_CantOpenFile), mf, NULL);
  1389.    return result;
  1390. }
  1391. ///
  1392. /// TR_ProcessSEND
  1393. //  Sends a list of messages
  1394. BOOL TR_ProcessSEND(struct Mail **mlist)
  1395. {
  1396.    struct TransStat ts;
  1397.    int c, i, port = 25, err;
  1398.    struct Mail *mail, *new;
  1399.    struct Folder *outfolder = FO_GetFolderByType(FT_OUTGOING, NULL);
  1400.    struct Folder *sentfolder = FO_GetFolderByType(FT_SENT, NULL);
  1401.    BOOL success = FALSE;
  1402.    char *p;
  1403.  
  1404.    G->TR->List = NULL;
  1405.    G->TR_Allow = G->TR->Abort = G->Error = FALSE;
  1406.    for (c = i = 0; i < (int)*mlist; i++)
  1407.    {
  1408.       mail = mlist[i+2];
  1409.       if (mail->Status == STATUS_WFS || mail->Status == STATUS_ERR) if (new = malloc(sizeof(struct Mail)))
  1410.       {
  1411.          *new = *mail;
  1412.          new->Index = ++c;
  1413.          new->Status = 1;
  1414.          new->Reference = mail;
  1415.          new->Next = NULL;
  1416.          MyAddTail(&(G->TR->List), new);
  1417.       }
  1418.    }
  1419.    if (c)
  1420.    {
  1421.       char host[SIZE_HOST];
  1422.       G->TR->Scnt = MA_AllocRules(G->TR->Search, APPLY_SENT);
  1423.       TR_TransStat_Init(&ts);
  1424.       TR_TransStat_Start(&ts);
  1425.       strcpy(host, C->SMTP_Server);
  1426.       if (p = strchr(host, ':')) { *p = 0; port = atoi(++p); }
  1427.       TR_SetWinTitle(FALSE, host);
  1428.       if (!(err = TR_Connect(host, port)))
  1429.       {
  1430.          BOOL connected;
  1431.  
  1432.          if (C->Use_SMTP_AUTH && C->SMTP_AUTH_User[0]) connected=TR_ConnectESMTP();
  1433.          else connected=TR_ConnectSMTP();
  1434.          if (connected)
  1435.          {
  1436.             success = TRUE;
  1437.             AppendLogVerbose(41, GetStr(MSG_LOG_ConnectSMTP), host, "", "", "");
  1438.             for (mail = G->TR->List; mail; mail = mail->Next)
  1439.             {
  1440.                if (G->TR->Abort || G->Error) break;
  1441.                ts.Msgs_Done++;
  1442.                TR_TransStat_NextMsg(&ts, mail->Index, -1, mail->Size, GetStr(MSG_TR_Sending));
  1443.                switch (TR_SendMessage(&ts, mail))
  1444.                {
  1445.                   case 0: MA_SetMailStatus(mail->Reference, STATUS_ERR);
  1446.                           TR_SendSMTPCmd("RSET", NULL);
  1447.                           break;
  1448.                   case 1: MA_SetMailStatus(mail->Reference, STATUS_SNT);
  1449.                           if (TR_ApplySentFilters(mail->Reference)) MA_MoveCopy(mail->Reference, outfolder, sentfolder, FALSE);
  1450.                           break;
  1451.                   case 2: MA_SetMailStatus(mail->Reference, STATUS_SNT);
  1452.                           if (TR_ApplySentFilters(mail->Reference)) MA_DeleteSingle(mail->Reference, FALSE);
  1453.                }
  1454.             }
  1455.             TR_DisconnectSMTP();
  1456.             AppendLogNormal(40, GetStr(MSG_LOG_Sending), (void *)c, host, "", "");
  1457.          }
  1458.       }
  1459.       else switch (err)
  1460.       {
  1461.          case -1: ER_NewError(GetStr(MSG_ER_UnknownSMTP), C->SMTP_Server, NULL); break;
  1462.          default: ER_NewError(GetStr(MSG_ER_CantConnect), C->SMTP_Server, NULL);
  1463.       }
  1464.       MA_FreeRules(G->TR->Search, G->TR->Scnt);
  1465.    }
  1466.    TR_AbortnClose();
  1467.    return success;
  1468. }
  1469. ///
  1470.  
  1471. /*** IMPORT ***/
  1472. /// TR_AbortIMPORTFunc
  1473. //  Aborts import process
  1474. void SAVEDS TR_AbortIMPORTFunc(void)
  1475. {
  1476.    TR_AbortnClose();
  1477. }
  1478. MakeHook(TR_AbortIMPORTHook, TR_AbortIMPORTFunc);
  1479. ///
  1480. /// TR_ProcessIMPORTFunc
  1481. //  Imports messages from a UUCP mailbox file
  1482. void SAVEDS TR_ProcessIMPORTFunc(void)
  1483. {
  1484.    struct TransStat ts;
  1485.    FILE *fh, *f = NULL;
  1486.  
  1487.    TR_TransStat_Init(&ts);
  1488.    if (ts.Msgs_Tot)
  1489.    {
  1490.       TR_TransStat_Start(&ts);
  1491.       if (fh = fopen(G->TR->ImportFile, "r"))
  1492.       {
  1493.          struct ExtendedMail *email;
  1494.          struct Mail *mail = G->TR->List;
  1495.          static char mfile[SIZE_MFILE];
  1496.          BOOL header = FALSE, body = FALSE;
  1497.          struct Folder *folder = G->TR->ImportBox;
  1498.          int btype = folder->Type;
  1499.          char buffer[SIZE_LINE], *stat;
  1500.  
  1501.          if (btype == FT_OUTGOING) stat = Status[STATUS_WFS];
  1502.          else if (btype == FT_SENT || btype == FT_CUSTOMSENT) stat = Status[STATUS_SNT];
  1503.          else stat = " ";
  1504.          while (fgets(buffer, SIZE_LINE, fh) && !G->TR->Abort)
  1505.          {
  1506.             if (!header && !strncmp(buffer, "From ", 5))
  1507.             {
  1508.                if (body)
  1509.                {
  1510.                   if (f)
  1511.                   {
  1512.                      fclose(f); f = NULL;
  1513.                      if (email = MA_ExamineMail(folder, mfile, stat, FALSE))
  1514.                      {
  1515.                         AddMailToList((struct Mail *)email, folder);
  1516.                         MA_FreeEMailStruct(email);
  1517.                      }
  1518.                   }
  1519.                   mail = mail->Next;
  1520.                }
  1521.                header = TRUE; body = FALSE;
  1522.                if (mail->Status & 1)
  1523.                {
  1524.                   ts.Msgs_Done++;
  1525.                   TR_TransStat_NextMsg(&ts, mail->Index, mail->Position, mail->Size, GetStr(MSG_TR_Importing));
  1526.                   f = fopen(MA_NewMailFile(folder, mfile, 0), "w");
  1527.                }
  1528.             } 
  1529.             else if (f && (header || body))
  1530.             { 
  1531.                fputs(buffer, f);
  1532.                TR_TransStat_Update(&ts, strlen(buffer));
  1533.             }
  1534.             if (header && !buffer[1]) { body = TRUE; header = FALSE; }
  1535.          }
  1536.          if (body && f)
  1537.          {
  1538.             fclose(f);
  1539.             if (email = MA_ExamineMail(folder, mfile, stat, FALSE))
  1540.             {
  1541.                AddMailToList((struct Mail *)email, folder);
  1542.                MA_FreeEMailStruct(email);
  1543.             }
  1544.          }
  1545.          fclose(fh);
  1546.          DisplayMailList(folder, G->MA->GUI.NL_MAILS);
  1547.          AppendLog(50, GetStr(MSG_LOG_Importing), (void *)ts.Msgs_Done, G->TR->ImportFile, folder->Name, "");
  1548.          DisplayStatistics(folder);
  1549.       }
  1550.    }
  1551.    TR_AbortnClose();
  1552. }
  1553. MakeHook(TR_ProcessIMPORTHook, TR_ProcessIMPORTFunc);
  1554. ///
  1555.  
  1556. /*** GET ***/
  1557. /// TR_AbortGETFunc
  1558. //  Aborts a POP3 download
  1559. void SAVEDS TR_AbortGETFunc(void)
  1560. {
  1561.    MA_FreeRules(G->TR->Search, G->TR->Scnt);
  1562.    TR_AbortnClose();
  1563.    TR_CloseTCPIP();
  1564.    G->TR->Checking = FALSE; DisplayStatistics((struct Folder *)-1);
  1565. }
  1566. MakeHook(TR_AbortGETHook, TR_AbortGETFunc);
  1567. ///
  1568. /// TR_LoadMessage
  1569. //  Retrieves a message from the POP3 server
  1570. BOOL TR_LoadMessage(struct TransStat *ts, int number)
  1571. {
  1572.    static char mfile[SIZE_MFILE];
  1573.    struct Folder *infolder = FO_GetFolderByType(FT_INCOMING, NULL);
  1574.    char msgnum[SIZE_SMALL], buf[SIZE_LINE], msgfile[SIZE_PATHFILE];
  1575.    FILE *f;
  1576.  
  1577.    stccpy(msgfile, MA_NewMailFile(infolder, mfile, 0), SIZE_PATHFILE);
  1578.    if (f = fopen(msgfile, "w"))
  1579.    {
  1580.       sprintf(msgnum, "%ld", number);
  1581.       if (TR_SendPopCmd(buf, "RETR", msgnum, 0))
  1582.       {
  1583.          int l = 0;
  1584.          char line[SIZE_LINE], *bufptr;
  1585.          BOOL done = FALSE;
  1586.  
  1587.          if (bufptr = strstr(buf, "\r\n")) bufptr += 2;
  1588.          while (!G->Error && !G->TR->Abort)
  1589.          {
  1590.             for (; *bufptr; bufptr++)
  1591.             {
  1592.                if (*bufptr != '\r') line[l++] = *bufptr;
  1593.                if (l == SIZE_LINE-1)
  1594.                {
  1595.                   TR_TransStat_Update(ts, l);
  1596.                   line[l] = 0; l = 0;
  1597.                   if (fputs(line, f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), mfile, NULL); break; }
  1598.                }
  1599.                if (*bufptr != '\n') continue;
  1600.                TR_TransStat_Update(ts, l+1);
  1601.                line[l] = 0; l = 0;
  1602.                if (line[0] == '.')
  1603.                   if (line[1] == '\n') { done = TRUE; break; }
  1604.                   else l = 1;  /* RFC 1725 */
  1605.                if (fputs(&line[l], f) == EOF) { ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), mfile, NULL); break; }
  1606.                l = 0;
  1607.             }
  1608.             if (done) break;
  1609.             if (TR_RecvDat(buf) <= 0) break;
  1610.             bufptr = buf;
  1611.          }
  1612.       }
  1613.       else ER_NewError(GetStr(MSG_ER_ErrorWriteMailfile), (char *)"", NULL);
  1614.       fclose(f);
  1615.       if (!G->TR->Abort && !G->Error)
  1616.       {
  1617.          struct ExtendedMail *mail;
  1618.          if (mail = MA_ExamineMail(infolder, mfile, " ", FALSE))
  1619.          {
  1620.             struct Mail *new = AddMailToList((struct Mail *)mail, infolder);
  1621.             if (FO_GetCurrentFolder() == infolder) DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_InsertSingle, new, MUIV_NList_Insert_Sorted);
  1622.             AppendLogVerbose(32, GetStr(MSG_LOG_RetrievingVerbose), AddrName(new->From), new->Subject, (void *)new->Size, "");
  1623.             MA_StartMacro(MACRO_NEWMSG, mfile);
  1624.             MA_FreeEMailStruct(mail);
  1625.          }
  1626.          return TRUE;
  1627.       }
  1628.       DeleteFile(msgfile);
  1629.    }
  1630.    return FALSE;
  1631. }
  1632. ///
  1633. /// TR_DeleteMessage
  1634. //  Deletes a message on the POP3 server
  1635. void TR_DeleteMessage(int number)
  1636. {
  1637.    char msgnum[SIZE_SMALL], buf[SIZE_LINE];
  1638.  
  1639.    sprintf(msgnum, "%ld", number);
  1640.    set(G->TR->GUI.TX_STATUS, MUIA_Text_Contents, GetStr(MSG_TR_DeletingServerMail));
  1641.    if (TR_SendPopCmd(buf, "DELE", msgnum, POPCMD_WAITEOL)) G->TR->Stats.Deleted++;
  1642. }
  1643. ///
  1644. /// TR_NewMailAlert
  1645. //  Notifies user when new mail is available
  1646. void TR_NewMailAlert(void)
  1647. {
  1648.    struct DownloadResult *stats = &G->TR->Stats;
  1649.  
  1650.    memcpy(&G->LastDL, stats, sizeof(struct DownloadResult));
  1651.    if (!stats->Downloaded) return;
  1652.    if ((C->NotifyType & NOTI_REQ) && G->TR->GUIlevel != POP_REXX)
  1653.    {
  1654.       int iconified;
  1655.       static char buffer[SIZE_LARGE];
  1656.       struct RuleResult *rr = &G->RRs;
  1657.       get(G->App, MUIA_Application_Iconified, &iconified);
  1658.       if (iconified) { PopUp(); Delay(50L); }
  1659.       sprintf(buffer, GetStr(MSG_TR_NewMailReq),
  1660.          stats->Downloaded, stats->OnServer-stats->Deleted, stats->DupSkipped);
  1661.       sprintf(&buffer[strlen(buffer)], GetStr(MSG_TR_FilterStats),
  1662.          rr->Checked, rr->Bounced, rr->Forwarded, rr->Replied, rr->Executed, rr->Moved, rr->Deleted);
  1663.       InfoWindow(GetStr(MSG_TR_NewMail), buffer, GetStr(MSG_Okay), G->MA->GUI.WI);
  1664.    }
  1665.    if (C->NotifyType & NOTI_CMD)   ExecuteCommand(C->NotifyCommand, FALSE, NULL);
  1666.    if (C->NotifyType & NOTI_SOUND) PlaySound(C->NotifySound);
  1667. }
  1668. ///
  1669. /// TR_ProcessGETFunc
  1670. //  Downloads messages from a POP3 server
  1671. void SAVEDS TR_ProcessGETFunc(void)
  1672. {
  1673.    struct TransStat ts;
  1674.    struct Mail *mail;
  1675.  
  1676.    TR_TransStat_Init(&ts);
  1677.    if (ts.Msgs_Tot)
  1678.    {
  1679.       if (C->TransferWindow == 2) set(G->TR->GUI.WI, MUIA_Window_Open, TRUE);
  1680.       TR_TransStat_Start(&ts);
  1681.       for (mail = G->TR->List; mail && !G->TR->Abort && !G->Error; mail = mail->Next)
  1682.       {
  1683.          TR_TransStat_NextMsg(&ts, mail->Index, mail->Position, mail->Size, GetStr(MSG_TR_Downloading));
  1684.          if (mail->Status & 1)
  1685.          {
  1686.             if (TR_LoadMessage(&ts, mail->Index))
  1687.             {
  1688.                G->TR->Stats.Downloaded++;
  1689.                if (C->AvoidDuplicates) TR_AppendUIDL(mail->UIDL);
  1690.                if (mail->Status & 2) TR_DeleteMessage(mail->Index);
  1691.             }
  1692.          }
  1693.          else if (mail->Status & 2)
  1694.          {
  1695.             TR_DeleteMessage(mail->Index);
  1696.          }
  1697.       }
  1698.       DisplayStatistics(FO_GetFolderByType(FT_INCOMING, NULL));
  1699.    }
  1700.    TR_GetMailFromNextPOP(FALSE, 0, 0);
  1701. }
  1702. MakeHook(TR_ProcessGETHook, TR_ProcessGETFunc);
  1703. ///
  1704. /// TR_GetMessageInfoFunc
  1705. //  Requests message header of a message selected by the user
  1706. void SAVEDS TR_GetMessageInfoFunc(void)
  1707. {
  1708.    int line;
  1709.    struct Mail *mail;
  1710.    get(G->TR->GUI.LV_MAILS, MUIA_NList_Active, &line);
  1711.    DoMethod(G->TR->GUI.LV_MAILS, MUIM_NList_GetEntry, line, &mail);
  1712.    TR_GetMessageDetails(mail, line);
  1713. }
  1714. MakeHook(TR_GetMessageInfoHook, TR_GetMessageInfoFunc);
  1715. ///
  1716. /// TR_CompleteMsgList
  1717. //  Gets details for messages on server
  1718. void TR_CompleteMsgList()
  1719. {
  1720.    struct TR_ClassData *tr = G->TR;
  1721.    struct Mail *mail = tr->GMD_Mail;
  1722.  
  1723.    if (C->PreSelection < 3) while (mail && !tr->Abort)
  1724.    {
  1725.       if (tr->Pause) return;
  1726.       if (tr->Start) { TR_ProcessGETFunc(); return; }
  1727.       if (C->PreSelection != 1 || mail->Size >= C->WarnSize*1024) TR_GetMessageDetails(mail, tr->GMD_Line++);
  1728.       mail = mail->Next;
  1729.    }
  1730.    set(G->TR->GUI.BT_PAUSE, MUIA_Disabled, TRUE);
  1731.    DoMethod(tr->GUI.BT_START, MUIM_KillNotify, MUIA_Pressed);
  1732.    DoMethod(tr->GUI.BT_START, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_ProcessGETHook);
  1733.    DoMethod(tr->GUI.BT_QUIT , MUIM_KillNotify, MUIA_Pressed);
  1734.    DoMethod(tr->GUI.BT_QUIT , MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_AbortGETHook);
  1735.    if (tr->Abort) TR_AbortGETFunc();
  1736. }
  1737. ///
  1738. /// TR_PauseFunc
  1739. //  Pauses or resumes message download
  1740. void SAVEDS ASM TR_PauseFunc(REG(a1,int *arg))
  1741. {
  1742.    BOOL pause = *arg;
  1743.  
  1744.    set(G->TR->GUI.BT_RESUME, MUIA_Disabled, !pause);
  1745.    set(G->TR->GUI.BT_PAUSE,  MUIA_Disabled, pause);
  1746.    if (pause) return;
  1747.    G->TR->Pause = FALSE;
  1748.    TR_CompleteMsgList();
  1749. }
  1750. MakeHook(TR_PauseHook, TR_PauseFunc);
  1751. ///
  1752.  
  1753. /*** GUI ***/
  1754. /// TR_LV_DspFunc
  1755. //  Message listview display hook
  1756. long SAVEDS ASM TR_LV_DspFunc(REG(a0,struct Hook *hook), REG(a2,char **array), REG(a1,struct Mail *entry))
  1757. {
  1758.    if (entry)
  1759.    {
  1760.       static char dispfro[SIZE_DEFAULT], dispsta[SIZE_DEFAULT], dispsiz[SIZE_SMALL], dispdate[32];
  1761.       struct Person *pe = &entry->From;
  1762.       sprintf(array[0] = dispsta, "%3ld ", entry->Index);
  1763.       if (entry->Status & 1) strcat(dispsta, "\033o[10]");
  1764.       if (entry->Status & 2) strcat(dispsta, "\033o[9]");
  1765.       if (entry->Size >= C->WarnSize<<10) strcat(dispsiz, MUIX_PH);
  1766.       array[1] = dispsiz; *dispsiz = 0;
  1767.       FormatSize(entry->Size, dispsiz);
  1768.       stccpy(array[2] = dispfro, AddrName((*pe)), SIZE_DEFAULT);
  1769.       array[3] = entry->Subject;
  1770.       array[4] = dispdate; *dispdate = 0;
  1771.       if (entry->Date.ds_Days) stccpy(dispdate, DateStamp2String(&entry->Date, C->SwatchBeat ? DSS_DATEBEAT : DSS_DATETIME), 32);
  1772.    }
  1773.    else
  1774.    {
  1775.       array[0] = GetStr(MSG_MA_TitleStatus);
  1776.       array[1] = GetStr(MSG_Size);
  1777.       array[2] = GetStr(MSG_From);
  1778.       array[3] = GetStr(MSG_Subject);
  1779.       array[4] = GetStr(MSG_Date);
  1780.       
  1781.    }
  1782.    return 0;
  1783. }
  1784. MakeHook(TR_LV_DspFuncHook,TR_LV_DspFunc);
  1785. ///
  1786. /// TR_New
  1787. //  Creates transfer window
  1788. struct TR_ClassData *TR_New(int TRmode)
  1789. {
  1790.    struct TR_ClassData *data;
  1791.  
  1792.    if (data = calloc(1,sizeof(struct TR_ClassData)))
  1793.    {
  1794.       APTR bt_all = NULL, bt_none = NULL, bt_loadonly = NULL, bt_loaddel = NULL, bt_delonly = NULL, bt_leave = NULL;
  1795.       APTR gr_sel, gr_proc, gr_win;
  1796.       BOOL fullwin = (TRmode == TR_GET || TRmode == TR_IMPORT);
  1797.  
  1798.       
  1799.       gr_proc = ColGroup(2), GroupFrameT(GetStr(MSG_TR_Status)),
  1800.          Child, data->GUI.TX_STATS = TextObject,
  1801.             MUIA_Text_Contents, GetStr(MSG_TR_TransferStats0),
  1802.             MUIA_Background,MUII_TextBack,
  1803.             MUIA_Frame     ,MUIV_Frame_Text,
  1804.             MUIA_Text_PreParse, MUIX_C,
  1805.          End,
  1806.          Child, VGroup,
  1807.             Child, data->GUI.GA_COUNT = GaugeObject,
  1808.                GaugeFrame,
  1809.                MUIA_Gauge_Horiz   ,TRUE,
  1810.                MUIA_Gauge_InfoText,GetStr(MSG_TR_MessageGauge0),
  1811.             End,
  1812.             Child, data->GUI.GA_BYTES = GaugeObject,
  1813.                GaugeFrame,
  1814.                MUIA_Gauge_Horiz   ,TRUE,
  1815.                MUIA_Gauge_InfoText,GetStr(MSG_TR_BytesGauge0),
  1816.             End,
  1817.          End,
  1818.          Child, data->GUI.TX_STATUS = TextObject,
  1819.             MUIA_Background,MUII_TextBack,
  1820.             MUIA_Frame     ,MUIV_Frame_Text,
  1821.          End,
  1822.          Child, data->GUI.BT_ABORT = MakeButton(GetStr(MSG_TR_Abort)),
  1823.       End;
  1824.       if (fullwin)
  1825.       {
  1826.          data->GUI.GR_LIST = VGroup, GroupFrameT(TRmode==TR_IMPORT ? GetStr(MSG_TR_MsgInFile) : GetStr(MSG_TR_MsgOnServer)),
  1827.             MUIA_ShowMe, TRmode==TR_IMPORT || C->PreSelection>=2,
  1828.             Child, NListviewObject,
  1829.                MUIA_CycleChain,1,
  1830.                MUIA_NListview_NList, data->GUI.LV_MAILS = NListObject,
  1831.                   MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default,
  1832.                   MUIA_NList_Format        , "W=-1 BAR,W=-1 MACW=9 P=\33r BAR,MICW=20 BAR,MICW=16 BAR,MICW=9 MACW=15",
  1833.                   MUIA_NList_DisplayHook   , &TR_LV_DspFuncHook,
  1834.                   MUIA_NList_AutoVisible   , TRUE,
  1835.                   MUIA_NList_Title         , TRUE,
  1836.                   MUIA_NList_TitleSeparator, TRUE,
  1837.                   MUIA_NList_DoubleClick   , TRUE,
  1838.                   MUIA_NList_MinColSortable, 0,
  1839.                   MUIA_Font, C->FixedFontList ? MUIV_NList_Font_Fixed : MUIV_NList_Font,
  1840.                   MUIA_ContextMenu         , NULL,
  1841.                   MUIA_NList_Exports, MUIV_NList_Exports_Cols,
  1842.                   MUIA_NList_Imports, MUIV_NList_Imports_Cols,
  1843.                   MUIA_ObjectID, MAKE_ID('N','L','0','4'),
  1844.                End,
  1845.             End,
  1846.          End;
  1847.          gr_sel = VGroup, GroupFrameT(GetStr(MSG_TR_Control)),
  1848.             Child, ColGroup(5),
  1849.                Child, bt_all = MakeButton(GetStr(MSG_TR_All)),
  1850.                Child, bt_loaddel = MakeButton(GetStr(MSG_TR_DownloadDelete)),
  1851.                Child, bt_leave = MakeButton(GetStr(MSG_TR_Leave)),
  1852.                Child, HSpace(0),
  1853.                Child, data->GUI.BT_PAUSE = MakeButton(GetStr(MSG_TR_Pause)),
  1854.                Child, bt_none = MakeButton(GetStr(MSG_TR_Clear)),
  1855.                Child, bt_loadonly = MakeButton(GetStr(MSG_TR_DownloadOnly)),
  1856.                Child, bt_delonly = MakeButton(GetStr(MSG_TR_DeleteOnly)),
  1857.                Child, HSpace(0),
  1858.                Child, data->GUI.BT_RESUME = MakeButton(GetStr(MSG_TR_Resume)),
  1859.             End,
  1860.             Child, ColGroup(2),
  1861.                Child, data->GUI.BT_START = MakeButton(GetStr(MSG_TR_Start)),
  1862.                Child, data->GUI.BT_QUIT = MakeButton(GetStr(MSG_TR_Abort)),
  1863.             End,
  1864.          End;
  1865.          gr_win = VGroup,
  1866.             Child, data->GUI.GR_LIST,
  1867.             Child, data->GUI.GR_PAGE = PageGroup,
  1868.                Child, gr_sel,
  1869.                Child, gr_proc,
  1870.             End,
  1871.          End;
  1872.       }
  1873.       else gr_win = gr_proc;
  1874.       data->GUI.WI = WindowObject,
  1875.          MUIA_Window_ID, MAKE_ID('T','R','A','0'+TRmode-TR_IMPORT),
  1876.          MUIA_Window_CloseGadget, FALSE,
  1877.          MUIA_Window_Activate, (TRmode == TR_IMPORT || TRmode == TR_EXPORT),
  1878.          MUIA_HelpNode, "TR_W",
  1879.          WindowContents, gr_win,
  1880.       End;
  1881.       if (data->GUI.WI)
  1882.       {
  1883.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  1884.          SetHelp(data->GUI.TX_STATUS,MSG_HELP_TR_TX_STATUS);
  1885.          SetHelp(data->GUI.BT_ABORT ,MSG_HELP_TR_BT_ABORT);
  1886.          if (fullwin)
  1887.          {
  1888.             set(data->GUI.BT_RESUME, MUIA_Disabled, TRUE);
  1889.             if (TRmode == TR_IMPORT)
  1890.             {
  1891.                set(data->GUI.BT_PAUSE, MUIA_Disabled, TRUE);
  1892.                set(bt_delonly        , MUIA_Disabled, TRUE);
  1893.                set(bt_loaddel        , MUIA_Disabled, TRUE);
  1894.                DoMethod(data->GUI.BT_START, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_ProcessIMPORTHook);
  1895.                DoMethod(data->GUI.BT_QUIT , MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_AbortIMPORTHook);
  1896.             }
  1897.             else
  1898.             {
  1899.                set(data->GUI.GR_PAGE, MUIA_Group_ActivePage, 1);
  1900.                DoMethod(data->GUI.BT_RESUME,MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_PauseHook,0);
  1901.                DoMethod(data->GUI.BT_PAUSE ,MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_PauseHook,1);
  1902.                DoMethod(data->GUI.BT_PAUSE, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Pause));
  1903.                DoMethod(data->GUI.LV_MAILS ,MUIM_Notify, MUIA_NList_DoubleClick,TRUE, MUIV_Notify_Application, 2, MUIM_CallHook, &TR_GetMessageInfoHook);
  1904.                DoMethod(bt_delonly,         MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,2);
  1905.                DoMethod(bt_loaddel,         MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,3);
  1906.                DoMethod(data->GUI.BT_START, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Start));
  1907.                DoMethod(data->GUI.BT_QUIT , MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Abort));
  1908.             }
  1909.             DoMethod(bt_loadonly,        MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,1);
  1910.             DoMethod(bt_leave,           MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &TR_ChangeStatusHook,0);
  1911.             DoMethod(bt_all,             MUIM_Notify, MUIA_Pressed, FALSE, data->GUI.LV_MAILS, 4, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_On, NULL);
  1912.             DoMethod(bt_none,            MUIM_Notify, MUIA_Pressed, FALSE, data->GUI.LV_MAILS, 4, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Off, NULL);
  1913.             DoMethod(data->GUI.LV_MAILS, MUIM_NList_UseImage, G->MA->GUI.BC_STAT[9], 9, 0);
  1914.             DoMethod(data->GUI.LV_MAILS, MUIM_NList_UseImage, G->MA->GUI.BC_STAT[10], 10, 0);
  1915.          }
  1916.          DoMethod(data->GUI.BT_ABORT, MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_WriteLong, TRUE, &(data->Abort));
  1917.          MA_ChangeTransfer(FALSE);
  1918.          return data;
  1919.       }
  1920.       free(data);
  1921.    }
  1922.    return NULL;
  1923. }
  1924. ///
  1925.